/* Filename: chkpass.c
 * Description: 验证用户输入的用户名与密码是否与系统中存储的密码匹配(影子密码文件/etc/shadow)
 *   gcc -Wall chkpass.c -o chkpass -lcrypto && sudo ./chkpass zh
 * Last modified: humble 20200315 14:10
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <shadow.h>
#include <unistd.h>

static void usage(void);

int main(int argc, char **argv) {
    if(argc != 2){ fprintf(stderr, "argc !=2"); usage(); exit(1); }

    char *passptr = getpass("PassWord:"); // getpass() 从终端读取密码，但会隐藏用户的输入(不回显到终端)
    if(passptr == NULL){ perror("getpass"); exit(1); }

    struct spwd *shadowline = NULL; // 包含用户的加密密码(sp_pwdp字段，格式$加密算法id$盐值salt$加密后的密码encrypted)
    shadowline = getspnam(argv[1]); // 从系统的影子密码文件(/etc/shadow)中获取指定用户(argv[1])的密码信息
    if(shadowline == NULL){ perror("getspnam"); exit(1); }

    // 使用sp_pwdp里的 $加密算法$盐值 对passptr进行加密操作
    char *passcryptedptr = crypt(passptr, shadowline->sp_pwdp);
    if(passcryptedptr == NULL){ perror("crypt"); exit(1); }

    if(!strcmp(passcryptedptr, shadowline->sp_pwdp)){ puts("ok"); }
    else{ puts("failed"); }
    return 0;
}

static void usage(void) {
#define USAGE "Usage:\n\
  chkpass <username>\n"
    printf(USAGE);
}
